package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import server.mapper.CustomClassloader;
import server.mapper.Host;
import server.mapper.Mapper;
import server.mapper.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.List;

/**
 * Minicat的主类
 */
public class Bootstrap {

    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {
        // 加载解析相关server.xml,并扫描对应app下的web.xml
        loadServer();
    }

    /**
     * 加载解析web.xml，初始化Servlet
     */
    private void loadServlet(String webapp, Mapper.MappedHost host) {
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(webapp + File.separator + "web.xml");
            Element rootElement = document.getRootElement();
            List<Element> servletNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < servletNodes.size(); i++) {
                Element element = servletNodes.get(i);
                // <servlet-name>demo1</servlet-name>
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");

                String servletName = servletNameElement.getStringValue();
                // <servlet-class>com.zhouchao.MyServlet</servlet-class>
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();
                String servletPath = servletClass.replaceAll("\\.", "\\\\");

                // 加载指定的类
                String repository = new File(webapp).getCanonicalPath() + File.separator;
                servletPath.substring(0, servletPath.lastIndexOf("\\"));
                servletPath = repository + "classes" + File.separator + servletPath + ".class";
                CustomClassloader customClassloader = new CustomClassloader(servletName, servletPath);
                Class<?> clazz = customClassloader.loadClass(servletClass);

                System.out.println(clazz.getClassLoader().toString());

                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /demo1
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

                host.addServlet(urlPattern, (HttpServlet) clazz.newInstance());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 通过server.xml加载配置，并读取应用下面的web.xml文件
     */
    private void loadServer() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> services = rootElement.selectNodes("//services");
            for (int i = 0; i < services.size(); i++) {

                Mapper mapper = new Mapper();

                Element element = services.get(i);
                // <Connector port="9000"/>
                Element connectorElement = (Element) element.selectSingleNode("Connector");
                String servletName = connectorElement.attribute("port").getValue();
                int port = Integer.parseInt(servletName);

                // <Host name="localhost" appBase="/Users/gavin/Desktop/webapps" />
                List<Element> hostElementList = element.selectNodes("./Engine/Host");
                for (int j = 0; j < hostElementList.size(); j++) {
                    Element hostElement = hostElementList.get(j);
                    String name = hostElement.attributeValue("name");
                    String appBase = hostElement.attributeValue("appBase");

                    Host host = new Host(name, appBase);
                    Mapper.MappedHost mappedHost = new Mapper.MappedHost(name, host);
                    mapper.getHosts().add(mappedHost);

                    // 根据appBase加载servlet
                    File file = new File(appBase);
                    if (!file.exists()) {
                        throw new RuntimeException("project not found");
                    }
                    loadServlet(appBase, mappedHost);
                }
                Service service = new Service();
                service.setPort(port);
                service.setMapper(mapper);
                service.start();
            }
        } catch (DocumentException | IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * Minicat 的程序启动入口
     *
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            // 启动Minicat
            bootstrap.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
